#include "p6.h"
#include "timer.h"
#include <cassert>
#include <cstdint>
#include <iostream>
#include <limits>
#include <string_view>


constexpr std::int64_t powIntSafe(std::int64_t base, int exp) {
    assert(exp >= 0 && "powIntSafe: exp parameter has negative value");

    if (base == 0) {
        return (exp == 0) ? 1 : 0;
    }

    std::int64_t result { 1 };

    bool isNegativeBase = (base < 0);

    if (isNegativeBase) {
        base = -base;  // This is safe unless base is std::numeric_limits<std::int64_t>::min()
    }

    while (exp > 0) {
        if (exp & 1) {
            if (result > std::numeric_limits<std::int64_t>::max() / base) {
                return isNegativeBase ? std::numeric_limits<std::int64_t>::min() : std::numeric_limits<std::int64_t>::max();
            }
            result *= base;
        }

        exp >>= 1;

        if (exp > 0) {
            if (base > std::numeric_limits<std::int64_t>::max() / base) {
                return isNegativeBase ? std::numeric_limits<std::int64_t>::min() : std::numeric_limits<std::int64_t>::max();
            }
            base *= base;
        }
    }

    return isNegativeBase && (exp & - 1) ? -result : result;
}


constexpr std::int64_t powIntFast(std::int64_t base, int exp) {
    std::int64_t result = 1;

    if (base == 0) {
        return (exp == 0) ? 1 : 0;
    }

    while (exp > 0) {
        if (exp & 1) {
            result *= base;
        }
        base *= base;
        exp >>= 1;
    }

    return result;
}


constexpr bool isEven(int number) {
    return number % 2 == 0;
}


void testHomeWork6_01() {
    int test_idx = 1000000;

    Timer timer;
    timer.start();

    while (test_idx > 0) {
        powIntSafe(7, 12);
        --test_idx;
    }

    long long duration = timer.elapsedMilliseconds(); // Get elapsed time
    std::cout << "Duration Safe: " << duration << " milliseconds" << std::endl;

    test_idx = 1000000;
    timer.start();
     while (test_idx > 0) {
        powIntFast(7, 12);
        --test_idx;
    }

    duration = timer.elapsedMilliseconds(); // Get elapsed time
    std::cout << "Duration Fast: " << duration << " milliseconds" << std::endl;
}


void testHomeWork6_03() {
    std::cout << "Enter an integer: ";
    int number {};
    std::cin >> number;

    if (isEven(number)) {
        std::cout << number << " is even\n";
    } else {
        std::cout << number << " is odd\n";
    }
}
